package com.util;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.input.SAXBuilder;

import com.entity.XmlBean;
import com.util.annotation.RequestMapping;
import com.util.annotation.RequestParam;
import com.util.annotation.enums.RequestMethodEnums;

public class XmlUtil {

	/**
	 * 用于记录所有的路径及对应的信息
	 */
	private static Map<String,XmlBean> xmls = new HashMap<String, XmlBean>();
	
	
	
	public static void main(String[] args) throws Exception {
		analytical();
	}
	
	
	/**
	 * <p>Title: AnalyticalXml</p>
	 * <p>Description: 从配置文件中解析得到要扫描的所有类</p>
	 * @return 所有的要扫描解析的类
	 * @throws Exception
	 * @author G.X  2016年8月10日 下午3:16:26
	 */
	public static Set<String> analyticalXml() throws Exception{
		Set<String> map = new HashSet<String>();
		/**
		 * 1.解析XML获得要扫描的包路径
		 * 
		 */
		SAXBuilder builder = new SAXBuilder();
		//配置文件路径
		String path = Thread.currentThread().getContextClassLoader().getResource("").getPath();  
		String fileName = "config.xml";
//		Document doc = builder.build(path+fileName);
		Document doc = builder.build(new File(path+fileName));//"resources/config.xml"
		Element root = doc.getRootElement();
		
		Set<String> classNames = null;
		
		//获取所有的 context
		@SuppressWarnings("unchecked")
		List<Element> contextList = root.getChildren("context");
		if(contextList == null || contextList.size() == 0){
			return map;
		}
		for(Element context : contextList){
			/*
			 * 取得 每一个 context 中的信息
			 */
			String basePackage = context.getAttributeValue("base-package");
			if(basePackage == null){
				throw new RuntimeException("扫描包路径为空！！！");
			}
			String[] packs = basePackage.split(",");
			for(String s : packs){
				/**
				 * 2.取得包路径下的所有类路径
				 */
				classNames = ClassUtils.getClassName(s, true);
				if(classNames != null){
					// 包下的类放入到返回对象中
					for(String className : classNames){
						map.add(className);
					}
				}
			}
		}
		return map;
	}
	
	/**
	 * 执行解析
	 * @return
	 * @throws Exception
	 */
	public static Map<String,XmlBean> analytical() throws Exception{
		System.out.println("-------> 执行解析！！！");
		
		/**
		 * 解析XML获得要扫描的包路径
		 * 
		 */
		Set<String> classNames = XmlUtil.analyticalXml();

		/*
		 * 根据类路径 解析类
		 * 取得：
		 * 		A.类上的路径+方法上的路径
		 *      B.方法参数注解中的名称
		 *      C.方法参数的类型Class
		 */
		for (String className : classNames) {
//			Class<?> classType = Class.forName("java.lang.String");
			Class<?> classType = Class.forName(className);
			// 判断该类是不是具备注解 RequestMapping
			if(!classType.isAnnotationPresent(RequestMapping.class)){
				// 不具备 则进行下一个循环
				continue;
			}
			RequestMapping inheritedTest = classType.getAnnotation(RequestMapping.class);
			// 取得该类的url路径
			String url = inheritedTest.value();
			
			// 取得该类下所有的 public 方法
			Method[] publicMethods = classType.getMethods();
			
			/*
			 * 取得public方法中所有带RequestMapping注解的方法
			 */
			for(Method method : publicMethods){
				// 不带 RequestMapping注解 跳过
				if(!method.isAnnotationPresent(RequestMapping.class)){
					continue;
				}
				XmlBean item = new XmlBean();
				item.setClassType(classType);
				item.setMethodName(method.getName());
				
				inheritedTest = method.getAnnotation(RequestMapping.class);
				RequestMethodEnums[] methodType = inheritedTest.method();
				if(methodType != null && methodType.length > 0){
					item.setMethodType(methodType);
				}
				// 类url路径+方法url路径
				url += inheritedTest.value();
				System.out.println("-------> 解析到url路径：" + url);
				
				List<String> param = new ArrayList<String>();
				
				Class<?>[] pars = method.getParameterTypes();
				item.setParamClass(pars);
				
				if(pars.length == 0){
					System.out.println("-------> "+method.getName()+"方法没有参数！！！");
					item.setParamNames(param);
					// 路径:对应的调用信息(类、方法、方法参数)
					xmls.put(url, item);
					continue;
				}
				
				Annotation[][] parameterAnnotations = method.getParameterAnnotations();
				for (Annotation[] parameterAnnotation : parameterAnnotations) {
					/*
					 * 如果该参数有注解RequestParam，则记录参数名
					 * 否则 仅记录参数class
					 */
					boolean flag = true;
					if(parameterAnnotation.length > 0){
						for (Annotation annotation : parameterAnnotation) {
							if (annotation instanceof RequestParam) {
								RequestParam requestParam = (RequestParam)annotation;
								param.add(requestParam.value());
								flag = false;
							}
						}
					}
					if(flag){
						param.add("");
					}
				}
				item.setParamNames(param);
				// 路径:对应的调用信息(类、方法、方法参数)
				xmls.put(url, item);
			}
		}
		System.out.println("-------> 结束解析！！！");
		return xmls;
	}
	
	/**
	 * 根据url路径 获得对应的信息
	 * @param urlPath
	 * @return
	 */
	public static XmlBean findByPath(String urlPath){
		return xmls.get(urlPath);
	}
}
